# -*- coding:utf-8 -*-

# author: firstoneyuan
# email: devops_yj@163.com

"""
使用Thread类创建线程的方法:
1. 创建Thread的实例,传给它一个函数
2. 创建Thread的实例,传给它一个可调用的类实例.
3. 派生Thread的子类,并创建子类的实例.
"""

import threading
from time import sleep,ctime


# 1. 创建Thread的实例,传给它一个函数
# threading模块的Thread类有一个join()方法,可以让主线程等待所有线程执行完毕.
"""
loops = [4,2]

def loop(nloop,nsec):
    print("start loop:",nloop,"at:",ctime())
    sleep(nsec)
    print("loop",nloop,"done at:",ctime())

def main():
    print("starting at:",ctime())
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = threading.Thread(target=loop,args=(i,loops[i]))
        threads.append(t)

    for i in nloops:  # start threads
        threads[i].start()

    for i in nloops:   # wait for all
        threads[i].join()  # threads to finish
    
    print("all done at:",ctime())

if __name__=='__main__':
    main()

'''
上述脚本说明:
使用Thread对象,实例化每个Thread对象时,把函数(target)和参数(args)传进去,然后点得到返回的Thread实例,实例化Thread和调用thread.thread.start_new_thread()的最大区别是新线程不会立即开始执行.
当所有线程分配完之后,通过调用每个线程的start()方法来开始执行.
为每个线程调用join()方法,join()方法将等待线程结束.
'''
"""


# 2. 创建 Thread 的实例,传给它一个可调用的类实例
# 提供了更加面向对象的方法
"""
loops = [4,2]

class ThreadFunc:
    def __init__(self,func,args,name=''):
        self.name = name
        self.func = func
        self.args = args
    
    def __call__(self):
        self.func(*self.args)

def loop(nloop,nsec):
    print("start loop:",nloop, "at:",ctime())
    sleep(nsec)
    print('loop:',nloop,'done at:',ctime())

def main():
    print("starting at:",ctime())
    threads = []
    nloops = range(len(loops))

    for i in nloops:  # create all threads
        t = threading.Thread(target=ThreadFunc(loop,(i,loops[i]),loop.__name__))
        threads.append(t)

    for i in nloops: # start all threads
        threads[i].start()
    
    for i in nloops:  # wait for completion
        threads[i].join()

    print("all done at:",ctime())

if __name__=='__main__':
    main()

'''
说明:
添加了ThreadFunc类,并在实例化Thread做了一些改动,同时实例化了可调用类ThreadFunc。完成了两个实例化.
ThreadFunc类保存了函数参数,函数自身,函数名的字符串.构造函数__init__()用于设定上述这些值.
当创建新线程时,Thread类的代码将调用ThreadFunc对象,此时会调用__call__()这个特殊方法.
'''
"""

# 3. 派生Thread的子类,并创建子类的实例.
loops = (4,2)

class MyThread(threading.Thread):
    def __init__(self,func,args,name=''):
        threading.Thread.__init__(self)
        self.name = name
        self.func = func 
        self.args = args 

    def run(self):
        self.func(*self.args)

def loop(nloop,nsec):
    print("start loop:",nloop,"at:",ctime())
    sleep(nsec)
    print("loop:",nloop,"done at:",ctime())

def main():
    print("starting at:",ctime())
    threads = []
    nloops = range(len(loops))

    for i in nloops:
        t = MyThread(loop,(i,loops[i]),loop.__name__)
        threads.append(t)

    for i in nloops:
        threads[i].start()
    
    for i in nloops:
        threads[i].join()

    print("all done at:",ctime())

if __name__=="__main__":
    main()